﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.IO;
using System.Reflection;

namespace PackZip
{
    public partial class MainFrom : Form
    {
        Dictionary<string, List<ServiceInfo>> list = new Dictionary<string, List<ServiceInfo>>();

        public MainFrom()
        {
            InitializeComponent();
        }

        private void MainFrom_Load(object sender, EventArgs e)
        {
            lblID.Text = "";
            lblName.Text = "";
            lblVersion.Text = "";
            lblDesc.Text = "";
            folderBrowserDialog1.SelectedPath = AppDomain.CurrentDomain.BaseDirectory;
        }

        private void btnSelectpath_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            list = PlugHelper.CheckType(folderBrowserDialog1.SelectedPath);

            if (list == null)
            {
                showerror("load type error.");
                return;
            }

            if (list.Count == 0)
            {
                showerror("no type.");
                return;
            }
            cboFiles.Items.Clear();
            foreach (string str in list.Keys)
            {
                cboFiles.Items.Add(str);
            }
            cboFiles.SelectedIndex = 0;
            cboFiles_SelectedIndexChanged(null, null);

            txtPath.Text = folderBrowserDialog1.SelectedPath;
            if (!txtPath.Text.EndsWith("\\"))
            {
                txtPath.Text += "\\";
            }
        }

        private void btnSelectSaveFile_Click(object sender, EventArgs e)
        {
            if (saveFileDialog1.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            txtSavePath.Text = saveFileDialog1.FileName;
        }
        string strTemplate = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<Plug><ID>{0}</ID><Name>{1}</Name><Type>{2}</Type><Version>{3}</Version><Description>{4}</Description></Plug>";
        private void btnSave_Click(object sender, EventArgs e)
        {
            ServiceInfo si = cbotypes.SelectedItem as ServiceInfo;
            try
            {
                using (MemoryStream mem = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(string.Format(strTemplate, si.ID, si.Name,
                    si.Type, si.Version, si.Description))))
                {
                    Dictionary<string, Stream> list = new Dictionary<string, Stream>();
                    list.Add(string.Format("{0}Main.xml", txtPath.Text), mem);
                    WindowServices.Common.ZipHelper.Zip(txtPath.Text, txtSavePath.Text, null, true, list);
                }
            }
            catch (Exception ee)
            {
                showerror(ee.Message);
                return;
            }

            MessageBox.Show("success");
        }

        private void showerror(string message)
        {
            MessageBox.Show(message, "Tips", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        private void cboFiles_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cboFiles.SelectedIndex != -1)
            {
                cbotypes.Items.Clear();
                foreach (ServiceInfo si in list[cboFiles.SelectedItem.ToString()])
                {
                    cbotypes.Items.Add(si);
                }
                if (cbotypes.Items.Count > 0)
                {
                    cbotypes.SelectedIndex = 0;
                    cbotypes_SelectedIndexChanged(null, null);
                }
            }
        }

        private void cbotypes_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbotypes.SelectedIndex != -1)
            {
                ServiceInfo si = cbotypes.SelectedItem as ServiceInfo;
                if (si != null)
                {
                    lblID.Text = si.ID.ToString();
                    lblName.Text = si.Name;
                    lblVersion.Text = si.Version.ToString();
                    lblDesc.Text = si.Description;
                }
            }

        }
    }

    [Serializable]
    public class ServiceInfo
    {
        public Guid ID
        {
            get;
            set;
        }

        public string Name { get; set; }
        public string Type { get; set; }

        public Version Version { get; set; }

        public string Description { get; set; }

        public override string ToString()
        {
            return Type;
        }
    }

    class PlugHelper : MarshalByRefObject
    {
        public PlugHelper() { }
        public static Dictionary<string, List<ServiceInfo>> CheckType(string folder)
        {
            AppDomain domain = null;
            Dictionary<string, List<ServiceInfo>> list = null;
            try
            {
                list = new Dictionary<string, List<ServiceInfo>>();
                //AppDomainSetup setup = new AppDomainSetup();
                //setup.PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory;
                //setup.DynamicBase = folder;

                domain = AppDomain.CreateDomain("temp");
                domain.AppendPrivatePath(folder);
                ObjectHandle oh = domain.CreateInstance(typeof(PlugHelper).Assembly.FullName, typeof(PlugHelper).FullName);
                PlugHelper ph = (PlugHelper)oh.Unwrap();
                List<ServiceInfo> list1 = null;
                FileInfo[] fis = new DirectoryInfo(folder).GetFiles("*.dll");
                foreach (FileInfo fi in fis )
                {
                    ph.LoadFile(fi.FullName);
                }
                foreach (FileInfo fi in fis )
                {
                    try
                    {
                        list1 = ph.GetServiceInfo(fi.FullName);
                        if (list1 != null && list1.Count > 0)
                        {
                            list.Add(fi.FullName, list1);
                        }
                    }
                    catch
                    {
                        continue;
                    }
                }
            }
            catch
            {
                list = null;
            }
            finally
            {
                if (domain != null)
                {
                    AppDomain.Unload(domain);
                }
            }
            return list;
        }

        Dictionary<string,Assembly> dic = new Dictionary<string,Assembly>();
        private void LoadFile(string filename)
        {
            Assembly assembly = Assembly.LoadFrom(filename);

            if(assembly != null)
            {
                dic.Add(filename,assembly);
            }
        }

        private List<ServiceInfo> GetServiceInfo(string filepath)
        {
            List<ServiceInfo> list = new List<ServiceInfo>();

            Assembly assembly = dic[filepath]; //Assembly.LoadFrom(filepath);
            if (assembly == null)
            {
                return list;
            }

            foreach (Type type in assembly.GetTypes())
            {
                if (type.IsInterface)
                {
                    continue;
                }

                foreach (Type t1 in type.GetInterfaces())
                {
                    if (t1.Equals(GetInterfaceType()))
                    {
                        ServiceInfo si = new ServiceInfo();
                        si.Version = assembly.GetName().Version;
                        si.Type = type.AssemblyQualifiedName;
                        foreach (object attr in type.GetCustomAttributes(false))
                        {
                            if (attr.GetType().Equals(typeof(DisplayNameAttribute)))
                            {
                                DisplayNameAttribute att = attr as DisplayNameAttribute;
                                si.Name = att.DisplayName;
                            }

                            if (attr.GetType().Equals(typeof(DescriptionAttribute)))
                            {
                                DescriptionAttribute att = attr as DescriptionAttribute;
                                si.Description = att.Description;
                            }

                            if (attr.GetType().Equals(typeof(System.Runtime.InteropServices.GuidAttribute)))
                            {
                                System.Runtime.InteropServices.GuidAttribute att = attr as System.Runtime.InteropServices.GuidAttribute;
                                si.ID = new Guid(att.Value);
                            }
                        }
                        if (!si.ID.Equals(Guid.Empty))
                        {
                            list.Add(si);
                        }
                        break;
                    }
                }
            }

            return list;
        }

        private bool CheckType1(string type)
        {
            object ob = Assembly.Load(type.Split(',')[1]).CreateInstance(type.Split(',')[0]);

            foreach (Type t in ob.GetType().GetInterfaces())
            {
                if (t.Equals(GetInterfaceType()))
                {
                    return true;
                }
            }

            return false;
        }
        private Type IType = null;
        private Type GetInterfaceType()
        {
            if (IType == null)
            {
                if (string.IsNullOrEmpty(System.Configuration.ConfigurationManager.AppSettings["Interface"]))
                {
                    IType = typeof(WindowServices.Interface.IService);
                }
                else
                {
                    try
                    {
                        string[] strs = System.Configuration.ConfigurationManager.AppSettings["Interface"].Split(new char[] { ',' }, 2);
                        if (strs.Length != 2)
                        {
                            IType = typeof(WindowServices.Interface.IService);
                        }
                        else
                        {
                            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
                            {
                                if (string.Compare(a.FullName, strs[1], true) == 0)
                                {
                                    Type t = a.GetType(strs[0], false, true);
                                    IType = t ?? typeof(WindowServices.Interface.IService);
                                    break;
                                }
                            }
                        }
                    }
                    catch
                    {
                        IType = typeof(WindowServices.Interface.IService);
                    }
                }
            }

            return IType;
        }

    }
}
